package ua.edu.sumdu.j2se.roman.lab1.domain;


import java.util.*;
/**
 * Author: Radko Roman.
 */

/**
 * This abstract class describes interface for extended classes ArrayTaskList and LinkedTaskList.
 *
 */
public abstract class TaskList implements Iterable<Task>, Cloneable {

    /**
     * This method adds new task to the task list.
     *
     * @param task new task to be added, not null
     * @throws IllegalArgumentException when task is null
     */
    public abstract void add(Task task);

    /**
     * This abstract method method means that in extended class must be implemented method size.
     *
     * @return  count of tasks in the list
     */
    public abstract int size();

    /**
     * This abstract method means that in extended class must be implemented method remove.
     * Just like add method in this must be passed Task type parameter.
     *
     * @param task  to be removed from the list
     */
    public abstract void remove(Task task);

    /**
     * This method returns array of the tasks which have start time that contained in time interval
     * from the initial time point that equals "from" parameter to final time point that equals "to" parameter.
     *
     * @param from  initial time point
     * @param to    final time point
     * @return      array of result elements
     */
    public Task[] incoming(Date from, Date to) {
        TaskList result = new ArrayTaskList();
        for (Task task : this) {
            if (task.isInInterval(from, to)) {
                result.add(task);
            }
        }
        return result.toArray();
    }

    /**
     * This method returns array of the tasks with length that equal count of all tasks in list.
     *
     * @return array of the tasks
     */
    public Task[] toArray() {
        Iterator<Task> it = iterator();
        Task[] result = new Task[size()];
        for (int i = 0; it.hasNext(); i++) {
            result[i] = it.next();
        }
        return result;
    }

    /**
     * This abstract method method means that in extended class must be implemented method iterator.
     *
     * @return  new Iterator<Task>
     */
    @Override
    public abstract Iterator<Task> iterator();

    /**
     * This method overwrite existing equals method with Object type parameter for extended classes (ArrayTaskList and LinkedTaskList).
     *
     * @param other object with type TaskList
     * @return      boolean
     */
    @Override
    public boolean equals(Object other) {
        if (this == other) return true;
        if (other == null || getClass() != other.getClass()) return false;

        TaskList tasks = (TaskList) other;
        if (size() != tasks.size()) {
            return false;
        }
        Iterator<Task> it1 = this.iterator();
        Iterator<Task> it2 = tasks.iterator();
        for (; it1.hasNext() && it2.hasNext(); ) {
            if (!it1.next().equals(it2.next())) {
                return false;
            }
        }
        return true;
    }

    /**
     * This method overwrite existing method hashCode for extended classes ArrayTaskList and LinkedTaskList.
     *
     * @return  hashCode of the task
     */
    @Override
    public int hashCode() {
        int result = 1;
        for (Task t : this) {
            result = 31 * result + (t == null ? 0 : t.hashCode());
        }
        return result;
    }

    /**
     * Determines date of the latest event.
     *
     * @return  latest date
     */
    public Date getLatestDate() {
        Date latest = new Date();
        for (Task task:this) {
            if (task.getEndTime().after(latest)) {
                latest = task.getEndTime();
            }
        }
        return latest;
    }

    /**
     * This method must return list of tasks in text string.
     *
     * @return  text string with the following structure: TaskList [Task1, Task2]
     */
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.getClass().getSimpleName());
        sb.append(" [");
        Iterator<Task> it = this.iterator();
        for (; it.hasNext(); ) {
            sb.append(it.next());
            if (it.hasNext()) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * This method performs duplicating of object TaskList type, with means creating a new object identical to current.
     *
     * @return  new TaskList
     * @throws  CloneNotSupportedException  thrown to indicate that the clone method in class Object has been called to clone an object, but that the 
	 *                                      object's class does not implement the Cloneable interface or object could not or should not be cloned.	                                        	                                                                            
     */
    @Override
    public TaskList clone() throws CloneNotSupportedException {
        return (TaskList) super.clone();
    };

}
